//****************************************************************************************
// Name:		proc.cpp
// Platform:	SQL Server 2000 SP3a or higher, Windows NT, 2000 or XP
// Author:		Copyright (c) 2006 by Michael Coles, MCDBA
//
// Description:	This code implements the xp_regex_search extended stored procedure.  This 
//				code is built upon the Boost Regex++ library.
//
// LEGAL STUFF:
// ------------
// Copyright (C) 2005 - 2006 by Michael Coles, MCDBA
//
// Some included code included is released under the redistribution agreements as 
// specified by the authors of the respective code.  Copyright holders of this included 
// code maintain all copyright and other rights to their original or derivative works.
//
// All rights reserved.                          
//
// REDISTRIBUTION OF THIS CODE:
// ----------------------------
// All code included in this package is either the original work of the copyright holder,
// or derivative work based on other copyright holders' works.  All derivative works 
// include information as required by the copright holders' redistribution agreements.
// These redistribution agreements, where possible, are included in the text of the source
// code distributed with this code.
//
// Redistribution and use in source and binary forms, with or without modification, are 
// permitted provided that the following conditions are met:
//
//   1. Redistributions of source code must retain the above copyright notice, this list 
//      of conditions and the following disclaimer.
//
//   2. Redistributions in binary form must reproduce the above copyright notice, this 
//      list of conditions and the following disclaimer in the documentation and/or other 
//      materials provided with the distribution.
//
//   3. The names of its contributors may not be used to endorse or promote products 
//      derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT 
// SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 
// WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//****************************************************************************************
//
// Pertaining to the Boost Regex++ library:
//
// The Boost Regex++ Library is Copyright (c) 1998-2000 by Dr John Maddock
// 
// Use, modification and distribution are subject to the Boost Software License, Version 
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at 
// http://www.boost.org/LICENSE_1_0.txt)

#define BOOST_REGEX_STATIC_LINK
#define BOOST_REGEX_NO_LIB 
#include <constants.h>
#include <dblib.h>
#include <params.h>
#include <boost/regex.hpp>
#include <stdafx.h>

using namespace boost;

#ifdef __cplusplus
extern "C" {
#endif

RETCODE __declspec(dllexport) xp_regex_search(SRV_PROC *srvproc);

#ifdef __cplusplus
}
#endif

RETCODE __declspec(dllexport) xp_regex_search(SRV_PROC *srvproc)
{	
	RETCODE rc = XP_NOERROR;
	int rowcount = 0;
	params *P1 = new params();
	params *P2 = new params();
	params *P3 = new params();
	BYTE *x = NULL;
	try
	{
		int numparams = params::getparamcount(srvproc);
		if (numparams != 3) {
			Dblib::printerror(srvproc, USAGE_REGEX_SEARCH);
			rc = XP_ERROR;
		}
		int case_i = boost::regbase::normal;	
		bool show_groups = false;
		if (rc == XP_NOERROR) {
			params::getparam(srvproc, 1, P1);
			params::getparam(srvproc, 2, P2);
			params::getparam(srvproc, 3, P3);
			if (P1->isoutput || P2->isoutput || P3->isoutput) {
				rc = XP_ERROR;
			}
		}
		if (rc == XP_NOERROR) {
			std::string options = strupr((char *)P3->cdata);
			int w = (int)options.find("G+");
			if (w > -1) {
				show_groups = true;
			}
			w = (int)options.find("I+");
			if (w > -1) {
				case_i |= boost::regbase::icase;
			}
			boost::regex e;
			boost::regex expression((const char *)P1->cdata, case_i);
			boost::match_results<std::string::const_iterator> what; 
			boost::match_flag_type flags = boost::match_default; 
			int Match_Num = 0;
			int Group_Num = 1;
			srv_describe(srvproc,
				1,
				(DBCHAR *)"MatchNum",
				9,
				SRVINT4,
				sizeof(SRVINT4),
				SRVINT4,
				sizeof(SRVINT4),
				NULL);
			srv_describe(srvproc,
				2,
				(DBCHAR *)"GroupNum",
				9,
				SRVINT4,
				sizeof(SRVINT4),
				SRVINT4,
				sizeof(SRVINT4),
				NULL);
			srv_describe(srvproc,
				3,
				(DBCHAR *)"MatchText",
				9,
				SRVBIGCHAR,
				8000,
				SRVBIGCHAR,
				8000,
				NULL);
			x = new BYTE[P2->length+1];
			memcpy(x, P2->cdata, P2->length);
			*(x + P2->length) = 0;
			std::string search_string = (const char *)x;
			std::string::const_iterator start, end;
			start = search_string.begin();
			end = search_string.end();
			while(regex_search(start, end, what, expression, flags) && start < end) 
			{
				if (what[0].str().length() > 0) {
					Match_Num++;
					if (show_groups == true) {
						for (Group_Num = 1; Group_Num < (int)what.size() + 1; Group_Num++) {
							srv_setcoldata(srvproc, 1, &Match_Num);
							srv_setcoldata(srvproc, 2, &Group_Num);
							std::string s = what[Group_Num - 1].str();
							srv_setcoldata(srvproc, 3, (BYTE *)s.c_str()); 
							srv_setcollen(srvproc, 3, (int)s.length());
							srv_sendrow(srvproc);
							rowcount++;
						}
					} else {
						Group_Num = 1;
						srv_setcoldata(srvproc, 1, &Match_Num);
						srv_setcoldata(srvproc, 2, &Group_Num);
						std::string t = what[0].str();
						srv_setcoldata(srvproc, 3, (BYTE *)t.c_str()); 
						srv_setcollen(srvproc, 3, (int)t.length());
						srv_sendrow(srvproc);
						rowcount++;
					}
				}
				start = (what[0].second == what[0].first) ? what[0].second + 1 : what[0].second;
				flags |= boost::match_prev_avail; 
				flags |= boost::match_not_bob; 
			}

		}
	} catch(boost::regex_error re) {
		Dblib::printerror(srvproc, ERR_REGEX_EXCEPTION);
		rc = XP_ERROR;
	} 
	srv_senddone(srvproc, SRV_DONE_MORE | SRV_DONE_COUNT, (DBUSMALLINT)0, (DBINT)rowcount);
	if (x != NULL)
		delete [] x;
	x = NULL;
	if (P1 != NULL)
		delete P1;
	P1 = NULL;
	if (P2 != NULL)
		delete P2;
	P2 = NULL;
	if (P3 != NULL)
		delete P3;
	P3 = NULL;
	return rc;
}

